package com.binary.repositroy.hibernate;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

import com.alibaba.fastjson.JSON;
/**
 * 
 * @author wangchangbo
 * @date 
 * @param <E>
 * sql查询工厂对象
 */
@Repository
public class HibernateBaseFace<E extends Serializable> {
	@PersistenceContext
	private EntityManager em;
	protected Class<E> entityClass = null;
	private  Logger logger = LoggerFactory.getLogger(HibernateBaseFace.class);
	@SuppressWarnings("unchecked")
	public HibernateBaseFace() {
		if(getClass().getGenericSuperclass() instanceof java.lang.reflect.ParameterizedType){
            	ParameterizedType type = (ParameterizedType)getClass().getGenericSuperclass();
            	this.entityClass= (Class<E>)type.getActualTypeArguments()[0]; 
		}
	}
	protected int bulkUpdateByMapSql(String sql,Map<String,Object>map){
		
		return this.bulkUpdateBySql(sql, map,null);
	}
	protected int bulkUpdateByArrSql(String sql,Object[] arr){
		
		return this.bulkUpdateBySql(sql,null,arr);
	}
	private int bulkUpdateBySql(String sql, Map<String, Object> map,
			Object[] arr) {
		if(sql!=null){
			Query query = em.createNativeQuery(sql);
			setPrameters(query,map,arr);
			logger.info(sql+"\n"+"\t"+JSON.toJSONString(map==null||map.size()==0?arr:map));
			return query.executeUpdate();
		}
		return 0;
	}
	protected Page<Object[]> getResultsByObjectMapSql(final String sql,final Map<String,Object> map,Pageable pageable){
		
		return  getResultsByObjectSql(sql,map,null,pageable);
	}
	protected Page<Object[]> getResultsByObjectArrSql(final String sql,final Object[] arr,Pageable pageable){
		return getResultsByObjectSql(sql,null,arr,pageable);
		
	}
	protected Page<Object[]>getResultsByObjectSql(final String sql,final Map<String,Object> map,final Object[] arr,final Pageable pageable){
		if(sql!=null&&pageable.getOffset()>=0&&pageable.getPageSize()>0){
			long count = getCountBySql(sql,map,arr);
			Query query = em.createNativeQuery(sql,entityClass);
			setPrameters(query,map,arr);
			logger.info(sql+"\n"+"\t"+JSON.toJSONString(map==null||map.size()==0?arr:map));
			query.setFirstResult(pageable.getOffset());
			query.setMaxResults(pageable.getPageSize());
			@SuppressWarnings("unchecked")
			List<Object[]> list = query.getResultList();
			return new PageImpl<Object[]>(list,pageable,count);
		}
		return null;
	}
	private long getCountBySql(String sql, Map<String, Object> map,
			Object[] arr) {
		if(sql!=null){
			Object o = findOneResultBySql("select count(1) from ("+sql+") table_1  where 1=1",map,arr);
			logger.info("select count(*) from ("+sql+") table_1  where 1=1");
			logger.info(JSON.toJSONString(map==null||map.size()==0?arr:map));
			return ((BigInteger)o).longValue();
		}
		return 0;
	}

	/*protected Object findOneResultByArr(String sql,
			Object[] arr) {
		return findOneResultBySql(sql,null,arr);
	}*/
	
	protected Object findOneResultByMap(String sql, Map<String, Object> map){
		return findOneResultBySql(sql,map,null);
	}

	protected  E findOneEntityByObjectArrSql(final String sql,final Object[] arr){
		return  findOneEntityBySql(sql,null,arr);
	}
	protected  E findOneEntityByMapSql(final String sql,final Map<String,Object> map){
		return findOneEntityBySql(sql,map,null);
	}
	
	
	@SuppressWarnings("unchecked")
	private  E findOneEntityBySql(String sql, Map<String, Object> map,
			Object[] arr) {
		if(sql!=null){
			Query query = em.createNativeQuery(sql,entityClass);
			setPrameters(query,map,arr);
			logger.info(sql+"\n"+"\t"+JSON.toJSONString(map==null||map.size()==0?arr:map));
			return (E)getSingleResult(query);
		}else{
			return null;
			
		}
	}
	
	/**
	 * @param query
	 * @return
	 */
	private Object getSingleResult(Query query) {
		Object obj=null;
		
		try {
			obj = query.getSingleResult();
		} catch (Exception e) {
			return null;
		}
		return obj;
	}
	private  Object findOneResultBySql(String sql, Map<String, Object> map,
			Object[] arr) {
		if(sql!=null){
			Query query = em.createNativeQuery(sql);
			setPrameters(query,map,arr);
			logger.info(sql+"\n"+"\t"+JSON.toJSONString(map==null||map.size()==0?arr:map));
			return query.getSingleResult();
		}else{
			return null;
			
		}
	}
	
	protected List<E> findAllEntityByObjectArrSql(final String sql,final Object[] arr){
		
		return findAllEntityBySql(sql,null,arr);
	}
	protected List<E> findAllEntityByMapSql(final String sql,final Map<String,Object> map){
		
		return findAllEntityBySql(sql,map,null);
	}
	
	@SuppressWarnings("unchecked")
	private List<E> findAllEntityBySql(final String sql,final Map<String,Object> map,final Object[] arr){
		
		if(sql!=null){
			Query query = em.createNativeQuery(sql,this.entityClass);
			setPrameters(query,map,arr);
			logger.info(sql+"\n"+"\t"+JSON.toJSONString(map==null||map.size()==0?arr:map));
			return query.getResultList();
		}else{
			return null;
		}
	}
	private void setPrameters(Query query, Map<String, Object> map, Object[] arr) {
		if(map!=null&&map.size()>0){
			for(Map.Entry<String, Object> entry:map.entrySet()){
				query.setParameter(entry.getKey(), entry.getValue());
			}
		}
		if(arr!=null&&arr.length>0){
			for(int i=0;i<arr.length;i++){
				query.setParameter(i+1, arr[i]);
			}
		}
	}
	
}
